import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;



//Player class is an abstract class that is extended by various characters

public abstract class Player {
	private int lifePoints;
	private int maxLimitLP = 120; // default is 120;
	private int energyPoints;
	private int maxLimitEP = 120; // default is 120;
	private Point location;
	private Color c;
	private boolean isRed; //True if the player is red team, false if the player is blue team
	
	// Damage each move does
	private int punchPoints;
	private int kickPoints;
	private int specialPoints;
	
	// Amount of energy each move consumes
	private int punchEnergy;
	private int kickEnergy;
	private int specialEnergy;
	
	//Old Jumping variables
	private boolean isJumping;
	private int jumpHeight = 28;
	private int jumpPixels;
	private int iDefault = 7;
	private int iFactor = iDefault;
	
	// Jump variables
	private int jumpMax;
	private int jumpCount;
	
	//Animation and Combat variables
	private ArrayList<BufferedImage> spritesR; // arrayList of bufferedImage of the characters facing right
	private ArrayList<BufferedImage> spritesL; // arrayList of bufferedImage of the characters facing left
	private int aniState; 
		/*
		 * state number 
		 * 0 == alert
		 * 1 == walk
		 * 2 == jump
		 * 3 == block
		 * 4 == punch
		 * 5 == kick
		 * 6 == jump kick
		 */
	private boolean isFacing; // true == facing left, false == facing right 
	private boolean isIdle; // true == able to do other move, false == unable to do other move
	private boolean isWalking; // true == player is moving, false == player is not moving
	private boolean isBlocking; // true == player is blocking, false == player is not blocking
	private int side; // walking side determined by keyCode variable
	private int sprite; // index of sprite in the arrayList
	private int countAni; // counts where the animation is in its sequence
	private int countFrame; // counts frame for timing
	private int alert; // index of last alert sprite in the arrayList 
	private int walk; // index of last walk sprite in the arrayList 
	private int jump; // index of last jump sprite in the arrayList 
	private int block;  // index of block sprite in the arrayList 
	private int blockHit; // index of block-while-being-hit sprite in the arrayList (same as block if there isn't one) 
	private int punchNum; // index of last punch sprite in the arrayList 
	private int kickNum; // index of last kick sprite in the arrayList 

	
 	public Player(int x, int y, boolean isRed, int kp, int ke, int pp, int pe, int sp, int se) throws IOException {


 		setIdle(true);
		setAniState(0);

		lifePoints = maxLimitLP;
		energyPoints = maxLimitEP;
		location = new Point(x, y);
		this.isRed = isRed;
		if(isRed)
			c = Color.red;
		else
			c = Color.blue;
		
		punchPoints = pp;
		kickPoints = kp;
		specialPoints = sp;
		
		punchEnergy = pe;
		kickEnergy = ke;
		specialEnergy = se;
		
		spritesR = new ArrayList<BufferedImage>();
		spritesL = new ArrayList<BufferedImage>();
	}
 	
	public abstract void loadSprites(int number);
	
	
	public void setPoint(Point p) {
		location = p;
	}
	
	public Point getPoint() {
		return location;
	}
	
	public boolean isNear(Player other, int number) {
		return Math.abs(distance(other)) <= number;
	}
	
	// Calculates the distance in x-coordinate from player to another player
	public int distance(Player other){
		return getPoint().getX() - other.getPoint().getX();
	}
	
 	public int getLifePoints() {
		return lifePoints;
	}

	public void setLifePoints(int lifePoints) {
		if(lifePoints > maxLimitLP)
			throw new IllegalArgumentException();
		this.lifePoints = lifePoints;
	}

	public int getEnergyPoints() {
		return energyPoints;
	}

	public void setEnergyPoints(int energyPoints) {
		if(energyPoints > maxLimitEP)
			setEnergyPoints(100);
		this.energyPoints = energyPoints;
	}
	
	public int getiDefault() {
		return iDefault;
	}

	public void setiDefault(int iDefault) {
		this.iDefault = iDefault;
	}
	
	public Color getColor(){
 		return c;
 	}
 	
 	public void setColor(Color c){
 		this.c = c;
 	}
 	
 	public boolean getTeam(){
 		return isRed;
 	}
 	
 	public boolean isDead() {
 		return lifePoints <= 0;
 	}
	
	
	public int getPunchPoints() {
		return punchPoints;
	}

	public void setPunchPoints(int punchPoints) {
		this.punchPoints = punchPoints;
	}

	public int getKickPoints(){
		return kickPoints;
	}
	
	public void setKickPoints(int kickPoints) {
		this.kickPoints = kickPoints;
	}

	public int getSpecialPoints() {
		return specialPoints;
	}

	public void setSpecialPoints(int specialPoints) {
		this.specialPoints = specialPoints;
	}
	
	public int getMaxLimitLP() {
		return maxLimitLP;
	}

	public void setMaxLimitLP(int maxLimitLP) {
		this.maxLimitLP = maxLimitLP;
	}

	public int getMaxLimitEP() {
		return maxLimitEP;
	}

	public void setMaxLimitEP(int maxLimitEP) {
		this.maxLimitEP = maxLimitEP;
	}

	// Energy stuff
	public void setPunchEnergy(int punchEnergy) {
		this.punchEnergy = punchEnergy;
	}

	public int getPunchEnergy() {
		return punchEnergy;
	}

	public void setKickEnergy(int kickEnergy) {
		this.kickEnergy = kickEnergy;
	}

	public int getKickEnergy() {
		return kickEnergy;
	}

	public void setSpecialEnergy(int specialEnergy) {
		this.specialEnergy = specialEnergy;
	}

	public int getSpecialEnergy() {
		return specialEnergy;
	}
	
	// Moves
	public void kick(Player other, int number, int damage, int energy) {
		if(!isDead()) {
			if(getEnergyPoints() > 0) {
				if(isNear(other, number) && (!other.isBlocking())) {
					setEnergyPoints(getEnergyPoints() - energy);
					other.setLifePoints(other.getLifePoints() - damage);
				} else if(isNear(other, number) && other.isBlocking()){
					setEnergyPoints(getEnergyPoints() - (int)(energy * 1.7));
					other.setLifePoints(other.getLifePoints() - (int)(damage / 2));
					other.setEnergyPoints(other.getEnergyPoints() - (int)(energy * 1.5));
				}else {
					setEnergyPoints(getEnergyPoints() - (int)(energy/2.2));
				}
			}
		}
	}
	
	public void punch(Player other, int number, int damage, int energy) {
		if(!isDead()) {
			if(getEnergyPoints() - getPunchEnergy() > 0) {
				if(isNear(other, number) && (!other.isBlocking())) {
					setEnergyPoints(getEnergyPoints() - energy);
					other.setLifePoints(other.getLifePoints() - damage);
				} else if(isNear(other, number) && other.isBlocking()){
					setEnergyPoints(getEnergyPoints() - (int)(energy * 1.5));
					other.setLifePoints(other.getLifePoints() - (int)(damage / 3));
					other.setEnergyPoints(other.getEnergyPoints() - (int)(energy * 1.3));
				} else {
					setEnergyPoints(getEnergyPoints() - (energy/2));
				}
			} 
		}
	}

	/* Special attack, caned for alpha version
	 * public void special(Player other, int number) {
		if(!isDead()) {
			if(getEnergyPoints() > 0) {
				if(isNear(other, number)) {
					setEnergyPoints(getEnergyPoints() - getSpecialEnergy());
					other.setLifePoints(other.getLifePoints() - getSpecialPoints());
				} else {
					setEnergyPoints(getEnergyPoints() - getSpecialEnergy());
				}
			}
		}
	}*/

	// Jumping
	public void setJumping(boolean isJumping) {
		this.isJumping = isJumping;
	}

	public boolean isJumping() {
		return isJumping;
	}

	public void setJumpHeight(int jumpHeight) {
		this.jumpHeight = jumpHeight;
	}

	public int getJumpHeight() {
		return jumpHeight;
	}

	public void setJumpPixels(int jumpPixels) {
		this.jumpPixels = jumpPixels;
	}

	public int getJumpPixels() {
		return jumpPixels;
	}

	public void setiFactor(int iFactor) {
		this.iFactor = iFactor;
	}

	public int getiFactor() {
		return iFactor;
	}

	// Animation related stuff
	
	public void setCountAni(int countAni) {
		this.countAni = countAni;
	}

	public int getCountAni() {
		return countAni;
	}

	public void setCountFrame(int countFrame) {
		this.countFrame = countFrame;
	}

	public int getCountFrame() {
		return countFrame;
	}

	public void setAniState(int aniState) {
		this.aniState = aniState;
	}

	public int getAniState() {
		return aniState;
	}

	public void setSprite(int sprite) {
		this.sprite = sprite;
	}

	public int getSprite() {
		return sprite;
	}
	
	public ArrayList<BufferedImage> getSpritesR(){
		return spritesR;
	}
	
	public ArrayList<BufferedImage> getSpritesL(){
		return spritesL;
	}
	
	public boolean isFacing(Player other){
		if(distance(other) < 0)
			isFacing = true; 
		else if(distance(other) > 0)
			isFacing = false;
		return isFacing;
	}

	public void setIdle(boolean isIdle) {
		this.isIdle = isIdle;
	}

	public boolean isIdle() {
		return isIdle;
	}

	public void setWalking(boolean isWalking) {
		this.isWalking = isWalking;
	}

	public boolean isWalking() {
		return isWalking;
	}

	public void setBlocking(boolean isBlocking) {
		this.isBlocking = isBlocking;
	}

	public boolean isBlocking() {
		return isBlocking;
	}
	
	public void setSide(int side) {
		this.side = side;
	}

	public int getSide() {
		return side;
	}
	
	public int getAlert(){
		return alert;
	}

	public void setAlert(int alert) {
		this.alert = alert;
	}
	
	public void setWalk(int walk) {
		this.walk = walk;
	}

	public int getWalk() {
		return walk;
	}

	public void setJump(int jump) {
		this.jump = jump;
	}

	public int getJump() {
		return jump;
	}

	
	public void setBlock(int block) {
		this.block = block;
	}

	
	public int getBlock() {
		return block;
	}

	public void setBlockHit(int blockHit) {
		this.blockHit = blockHit;
	}

	public int getBlockHit() {
		return blockHit;
	}
	
	public void setPunchNum(int punchNum) {
		this.punchNum = punchNum;
	}

	public int getPunchNum() {
		return punchNum;
	}

	public void setKickNum(int kickNum) {
		this.kickNum = kickNum;
	}

	public int getKickNum() {
		return kickNum;
	}

	public void setJumpMax(int jumpMax) {
		this.jumpMax = jumpMax;
	}

	public int getJumpMax() {
		return jumpMax;
	}

	public void setJumpCount(int jumpCount) {
		this.jumpCount = jumpCount;
	}

	public int getJumpCount() {
		return jumpCount;
	}




}